#include "qdebug.h"
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>

using namespace std;

namespace LockDemo{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int count = 0;

void* consume(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        qDebug("************************consume begin lock\n");
        qDebug("************************consumed %d\n",count);
        count++;
        sleep(2);
        qDebug("************************consume over lock\n");
        pthread_mutex_unlock(&mutex);
        qDebug("************************I'm out of pthread_mutex\n");
        sleep(1);
    }

    return NULL;
}

void* produce( void * arg )
{
    while(1)
    {
        pthread_mutex_lock(&mutex );
        qDebug("product begin lock\n");
        qDebug("produced %d\n", count);
        qDebug("product over lock\n");
        pthread_mutex_unlock(&mutex );
        qDebug("I'm out of pthread_mutex\n");
        sleep(1);
    }

    return NULL;
}

int main( void )
{
    pthread_t thread1,thread2;
    pthread_create(&thread1, NULL, &produce, NULL );
    pthread_create(&thread2, NULL, &consume, NULL );
    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    return 0;
}
}


namespace TryLockDemo{
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
int count = 0;

void* consume(void *)
{
    while(1)
    {
        pthread_mutex_lock(&mutex);
        qDebug("************************consume begin lock\n");
        qDebug("************************consumed %d\n",count);
        count++;
        sleep(2);
        qDebug("************************consume over lock\n");
        pthread_mutex_unlock(&mutex);
        qDebug("************************I'm out of pthread_mutex\n");
        sleep(1);
    }

    return NULL;
}

void* produce( void *  )
{
    while(1)
    {
        if(pthread_mutex_trylock(&mutex ) == 0)
        {
            qDebug("product begin lock\n");
            qDebug("produced %d\n", count );
            qDebug("product over lock\n");
            pthread_mutex_unlock(&mutex);
            qDebug("I'm out of pthread_mutex\n");
            sleep(1);
        }
        else
        {
            qDebug("I have try!But i can`t lock the mutex!\n");
            sleep(1);
        }
    }

    return NULL;
}

int main( void )
{
    pthread_t thread1,thread2;
    pthread_create(&thread1, NULL, &produce, NULL );
    pthread_create(&thread2, NULL, &consume, NULL );
    pthread_join(thread1,NULL);
    pthread_join(thread2,NULL);
    return 0;
}
}


namespace RwLockDemo{
static pthread_rwlock_t rwlock; //读写锁对象

int count = 0;

void *thread_function_read(void *)
{
    while(1)
    {
        pthread_rwlock_rdlock(&rwlock);
        qDebug("************************%d, read count %d\n", pthread_self(), count);
        sleep(1);
        pthread_rwlock_unlock(&rwlock);
        usleep(100);
    }

    return NULL;
}

void *thread_function_write(void *)
{
    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        count++;
        qDebug("************************%d, write count %d\n", pthread_self(), count);
        sleep(5);
        pthread_rwlock_unlock(&rwlock);
        usleep(100);
    }
    return NULL;
}

int main()
{
    pthread_t rpthread1, rpthread2, wpthread;

    pthread_rwlock_init(&rwlock,NULL);

    pthread_create(&rpthread1, NULL, thread_function_read, NULL);
    pthread_create(&rpthread2, NULL, thread_function_read, NULL);
    pthread_create(&wpthread, NULL, thread_function_write, NULL);

    pthread_join(rpthread1, NULL);
    pthread_join(rpthread2, NULL);
    pthread_join(wpthread, NULL);

    pthread_rwlock_destroy(&rwlock);
    exit(EXIT_SUCCESS);
}
}

namespace RwLockPriorDemo{
static pthread_rwlock_t rwlock; //读写锁对象
//读写锁优先级的使用
int count = 0;

void *thread_function_read(void *)
{
    while(1)
    {
        pthread_rwlock_rdlock(&rwlock);
        qDebug("************************%d, read count %d\n", pthread_self(), count);
        sleep(1);
        pthread_rwlock_unlock(&rwlock);
        //usleep(100);
    }

    return NULL;
}

void *thread_function_write(void *)
{
    while(1)
    {
        pthread_rwlock_wrlock(&rwlock);
        count++;
        qDebug("************************%d, write count %d\n", pthread_self(), count);
        sleep(1);
        pthread_rwlock_unlock(&rwlock);
        usleep(100);
    }
    return NULL;
}

int main()
{
    pthread_t rpthread1, rpthread2, wpthread;

    pthread_rwlockattr_t attr;
    // pthread_rwlockattr_setkind_np(&attr,PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP);

    pthread_rwlock_init(&rwlock, &attr);

    pthread_create(&rpthread1, NULL, thread_function_read, NULL);
    pthread_create(&rpthread2, NULL, thread_function_read, NULL);
    pthread_create(&wpthread, NULL, thread_function_write, NULL);

    pthread_join(rpthread1, NULL);
    pthread_join(rpthread2, NULL);
    pthread_join(wpthread, NULL);

    pthread_rwlock_destroy(&rwlock);
    exit(EXIT_SUCCESS);
}
}

namespace ThreadDemo {

#define NUM_THREADS     5

struct thread_data{
    int  thread_id;
    char *message;
};

void *PrintHello(void *threadarg)
{
    sleep(2);
    struct thread_data *my_data;

    my_data = (struct thread_data *) threadarg;
    qDebug("Thread ID : %d   Message : %s",my_data->thread_id,my_data->message);
    pthread_exit(NULL);
    return 0;
}


void *thread1(void *arg)
{
    const char *s=(char *)arg;
    qDebug("This is a pthread1.\n");
    qDebug("%s\n",s);
    pthread_exit((void*)"the first return!");  //结束线程，返回一个值。
    return 0;
}
void *thread2(void *arg)
{
    const char *s=(char *)arg;
    int *a = new int(21);
    qDebug("This is a pthread2.\n");
    qDebug("%s\n",s);
    pthread_exit((void*)a);
    return 0;
}

void *new_thread_start(void *){
    qDebug("新线程 start\n");
    //   _sleep(2000);

    int i=0;
    while(i++<NUM_THREADS)
    {
        qDebug("--%d",i);
        // usleep(200000);
        sleep(1);
    }
    qDebug("新线程 end\n");
    pthread_exit((void *)10);
    return 0;
}


}

namespace ThreadDemo {
void main ()
{
    RwLockDemo::main();
    TryLockDemo::main();
    return;
    LockDemo::main();

    {
        pthread_t tid;
        void *tret;
        int ret;
        ret = pthread_create(&tid, NULL, new_thread_start, NULL);
        if (ret) {
            qDebug("pthread_create error: %s\n", strerror(ret));
            exit(-1);
        }
        ret = pthread_join(tid, &tret);
        if (ret) {
            qDebug( "pthread_join error: %s\n", strerror(ret));
            exit(-1);
        }
        qDebug("新线程终止, code=%ld\n", tret);
    }




    {
        pthread_t threads[NUM_THREADS];
        struct thread_data td[NUM_THREADS];
        int rc;

        for(int i=0; i < NUM_THREADS; i++ ){
            cout <<"main() : creating thread, " << i << endl;
            td[i].thread_id = i;
            td[i].message = (char*)"This is message";
            rc = pthread_create(&threads[i], NULL,
                                PrintHello, (void *)&td[i]);
            if (rc){
                cout << "Error:unable to create thread," << rc << endl;
                exit(-1);
            }
        }
        for(int i=0; i < NUM_THREADS; i++ )
            pthread_join(threads[i],NULL);
        qDebug ("pthread_join end!\n");
    }

    {
        pthread_t id1,id2;
        void *a1,*a2;
        int ret1,ret2;
        char s1[]="This is first thread!";
        char s2[]="This is second thread!";

        ret1=pthread_create(&id1,NULL,thread1,s1);

        ret2=pthread_create(&id2,NULL, thread2,s2);

        if(ret1!=0){
            qDebug ("Create pthread1 error!\n");
            exit (1);
        }
        pthread_join(id1,&a1);

        qDebug("%s\n",(char*)a1);

        if(ret2!=0){
            qDebug ("Create pthread2 error!\n");
            exit (1);
        }
        qDebug("This is the  main process.\n");
        pthread_join(id2,&a2);
        qDebug("%d\n",*(int*)a2);
    }

}
}
